
#include "RealTimeDealCache.h"

#include <map>

namespace detail {
RealTimeDealCache::RealTimeDealCache(int64_t state)
    : m_id_start(-1), m_id_end(-1), m_capcity(32), m_state_id(state) {}

RealTimeDealCache::~RealTimeDealCache() {
  for (RecordVecList::iterator it = m_records.begin(); it != m_records.end();
       ++it) {
    RecordBatch* batch = *it;
    if (batch) {
      batch->clear();
      delete batch;
    }
  }
  m_records.clear();
}

void RealTimeDealCache::Add(int id, const Record* record) {
  if (!m_records.empty()) {
    RecordBatch* last = m_records.back();
    if (last->m_batch == id) {
      // BASSERTS(!last->empty(), "");
      last->push_back(*record);
      return;
    }
  }

  RecordBatch* batch = NULL;
  if ((int)m_records.size() >= m_capcity) {
    // BASSERTS(m_id_start < m_id_end && m_id_start >= 0, "");
    batch = m_records.front();
    m_records.pop_front();
    batch->clear();
    RecordBatch* next = m_records.front();
    m_id_start = next->m_batch;
  } else {
    batch = new RecordBatch();
  }
  batch->m_batch = id;
  batch->push_back(*record);
  m_records.push_back(batch);

  if (m_id_end < 0) {
    m_id_start = m_id_end = id;
  } else if (m_id_end < id)
    m_id_end = id;
}

bool RealTimeDealCache::GetSince(int id, Callback& callback) {
  // 用于枚举从id到最新m_batchid的所有Records
  // BASSERT(id <= m_id_end);

  // 应该先将要删除的记录找到,全部删除,然后在逐个添加
  // 因为RealTimeDealList中的m_values会将要删除的记录保留,其m_dealStatus为>=4
  // 而ui中的对应key会依旧存在,不删除,最终插入记录,会在m_values中找到,但值已经更新

  class OverlaySplitList {
    struct RecordInfo {
      RecordBatch* batch;
      int index;    // RecordBatch中的索引
      int batchid;  // RecordBatch的成员
      int sortid;
      bool remove;  // rd.m_body.m_dealStatus >=4
     public:
      bool operator<(const RecordInfo& rhs) const {
        return sortid < rhs.sortid;
      }
    };
    typedef std::vector<RecordInfo> RecordInfoVec;
    typedef std::map<std::string, RecordInfo> RecordInfoMap;
    RecordInfoMap m_infomap;
    int m_nextid;

   public:
    OverlaySplitList() : m_nextid(0) {}
    void AddRecordInfo(RecordBatch* batch, int index, bool remove) {
      // 保证DealIndex不重复
      // BASSERTS(batch && index >= 0 && index < (int)batch->size(), "");
      const MarketStreamInfo& info = batch->at(index);
      std::string key(info.m_body.m_id);
      RecordInfoMap::iterator it = m_infomap.find(key);
      if (it != m_infomap.end()) {
        RecordInfo& ri = it->second;
        ri.batch = batch;
        ri.batchid = batch->m_batch;
        ri.index = index;
        ri.remove = remove;
        ri.sortid = m_nextid++;
      } else {
        RecordInfo ri;
        ri.batch = batch;
        ri.batchid = batch->m_batch;
        ri.index = index;
        ri.remove = remove;
        ri.sortid = m_nextid++;
        m_infomap[key] = ri;
      }
    }
    void SplitRemovedAdded(RealTimeDealCache::Callback& callback) {
      RecordInfoVec all;
      all.reserve(m_infomap.size());
      for (RecordInfoMap::iterator it = m_infomap.begin();
           it != m_infomap.end(); ++it) {
        const RecordInfo& ri = it->second;
        all.push_back(ri);
      }
      if (all.size() > 1) {
        std::sort(all.begin(), all.end());
      }

      RecordInfoVec removed;
      RecordInfoVec added;
      for (int i = 0; i < (int)all.size(); i++) {
        if (all[i].remove)
          removed.push_back(all[i]);
        else
          added.push_back(all[i]);
      }

      // 先删除,后追加
      for (int i = 0; i < (int)removed.size(); i++) {
        const RecordInfo& ri = removed[i];
        callback.OnRecord(ri.batch->m_batch, &ri.batch->at(ri.index));
      }
      for (int i = 0; i < (int)added.size(); i++) {
        const RecordInfo& ri = added[i];
        if (!callback.OnRecord(ri.batch->m_batch, &ri.batch->at(ri.index)))
          break;
      }
    }
  };
  OverlaySplitList splitList;
  // 第一步定位到比id大的位置,后续可以使用哈希表来加速
  RecordVecList::iterator it = m_records.begin();
  for (; it != m_records.end(); it++) {
    RecordBatch* batch = *it;
    if (batch->m_batch <= id) continue;
    for (int i = 0; i < (int)batch->size(); i++) {
      const Record& rd = batch->at(i);
      int nDealStatus = atoi(rd.m_body.m_dealStatus);
      splitList.AddRecordInfo(batch, i, nDealStatus >= 4 && nDealStatus != 8);
    }
  }
  splitList.SplitRemovedAdded(callback);
  return true;
}

}  // namespace detail